using System;
using System.Collections.Generic;
using System.Linq;
using Xunit;
using Xunit.Abstractions;

namespace SmartSite.Frame.Test
{
    public class TestBytesExtention
    {
        const byte DLE = 0xfe;    // DLE STX 帧头 DLE ETX 帧尾 数据中有DLE,使用DLE DLE替代

        private readonly ITestOutputHelper Output;


        public TestBytesExtention(ITestOutputHelper output)
        {
            Output = output;
        }

        [Theory]
        [InlineData(new byte[] { 1, 2, DLE, 3, 4 }, new byte[] { 1, 2, DLE, DLE, 3, 4 }, new byte[] { 1, 2, DLE, 3, 4, 0 })]
        [InlineData(new byte[] { 1, 2, DLE, DLE, 3, 4 }, new byte[] { 1, 2, DLE, DLE, DLE, DLE, 3, 4 }, new byte[] { 1, 2, DLE, DLE, 3, 4, 0, 0 })]
        [InlineData(new byte[] { DLE, DLE, 3, 4 }, new byte[] { DLE, DLE, DLE, DLE, 3, 4 }, new byte[] { DLE, DLE, 3, 4, 0, 0 })]
        [InlineData(new byte[] { 1, 2, DLE, DLE }, new byte[] { 1, 2, DLE, DLE, DLE, DLE }, new byte[] { 0, 2, DLE, DLE })]
        public void TestDuplicateDle(IList<byte> source, IList<byte> target, IList<byte> flaseTarget)
        {
            Assert.Equal(target.Count, source.ToList().DuplicateDle().Count);
            Assert.Equal(target, source.ToList().DuplicateDle());
            Assert.NotEqual(flaseTarget, source.ToList().DuplicateDle());
        }

        [Theory]
        [InlineData(new byte[] { 1, 2, DLE, DLE, DLE, DLE }, new byte[] { 1, 2, DLE, DLE }, new byte[] { 0, 2, DLE, DLE })]
        [InlineData(new byte[] { DLE, DLE, DLE, DLE, 3, 4 }, new byte[] { DLE, DLE, 3, 4 }, new byte[] { DLE, DLE, 3, 0 })]
        [InlineData(new byte[] { 1, 2, DLE, DLE, DLE, DLE, 3, 4 }, new byte[] { 1, 2, DLE, DLE, 3, 4 }, new byte[] { 1, 2, DLE, DLE, 3, 0 })]
        [InlineData(new byte[] { 1, 2, DLE, DLE, DLE, 3, 4 }, new byte[] { 1, 2, DLE, DLE, 3, 4 }, new byte[] { 1, 2, DLE, DLE, 3, 0 })]
        [InlineData(new byte[] { 1, 2, DLE, DLE, 3, 4 }, new byte[] { 1, 2, DLE, 3, 4 }, new byte[] { 1, 2, DLE, 3, 0 })]
        [InlineData(new byte[] { 1, 2, DLE, 3, 4 }, new byte[] { 1, 2, DLE, 3, 4 }, new byte[] { 1, 2, DLE, 3, 0 })]
        public void TestRemoveDuplicateDle(IList<byte> source, IList<byte> target, IList<byte> flaseTarget)
        {
            Assert.Equal(target.Count, source.ToList().RemoveDuplicateDle().Count);
            Assert.Equal(target, source.ToList().RemoveDuplicateDle());
            Assert.NotEqual(flaseTarget, source.ToList().RemoveDuplicateDle());
        }

        [Theory]
        [InlineData(100)]
        public void TestPackFrame(int length)
        {
            //Given
            byte[] source = new byte[length];
            for (int i = 0; i < length; i++)
                source[i] = (byte)i;

            //When
            byte[] targetByOperating = source.PackFrameForSynchronization().ToArray();
            byte[] targetByOrigin = Origin.hex_to_uart_pkt(source, (ushort)source.Length);

            //Then
            Assert.Equal(targetByOrigin.Length, targetByOperating.Length);
            Assert.Equal(targetByOrigin, targetByOperating);
        }

        [Theory]
        [InlineData(100)]
        public void TestRestoreFrame(int length)
        {
            //Given
            byte[] source = new byte[length];
            for (int i = 0; i < length; i++)
                source[i] = (byte)i;

            source = source.PackFrameForSynchronization().ToArray();

            //When
            byte[] targetByOperating = source.UnpackFrameForSynchronization().ToArray();
            byte[] targetByOrigin = Origin.UDP_ReceivedAnalyze(source, (ushort)source.Length);

            //Then
            Assert.Equal(targetByOrigin.Length, targetByOperating.Length);
            Assert.Equal(targetByOrigin, targetByOperating);
        }
    }

    public class Origin
    {
        const byte DLE = 0xfe;
        const byte STX = 0xfb;
        const byte ETX = 0xfa;

        public static byte[] UDP_ReceivedAnalyze(byte[] hex_buf, UInt16 hex_buf_len)
        {

            List<byte> tempbuf = new List<byte>();
            tempbuf.AddRange(hex_buf);
            return UDP_ReceivedAnalyze(tempbuf, hex_buf_len);
        }

        public static byte[] UDP_ReceivedAnalyze(List<byte> hex_buf, UInt16 hex_buf_len)
        {
            byte[] buftemp = new byte[hex_buf_len];
            UInt16 y = 0;
            byte dlecount = 0;

            if (hex_buf_len == 4)
            {
                return null;
            }

            for (UInt16 i = 0; i < (UInt16)(hex_buf_len - 4 - dlecount); i++)//当有DLE时，减去delcount
            {
                if (hex_buf[y + 2] == DLE)
                {
                    y++;//如果是DLE 则去掉一个，后续数据跟上
                    dlecount++;
                }
                buftemp[i] = hex_buf[y + 2];
                y++;
            }
            hex_buf_len = (UInt16)(hex_buf_len - 4 - dlecount);//当有DLE时，减去delcount

            byte[] result = new byte[hex_buf_len];
            for (int i = 0; i < hex_buf_len; i++)
                result[i] = buftemp[i];

            return result;
        }

        /// <summary>
        /// 为下行帧添加头部和尾部
        /// </summary>
        /// <param name="hex_buf">数据</param>
        /// <param name="hex_buf_len">长度</param>
        /// <returns></returns>
        public static byte[] hex_to_uart_pkt(byte[] hex_buf, UInt16 hex_buf_len)
        {
            byte[] hex_buf_temp = new byte[hex_buf_len + 200];

            UInt16 index = 0;
            UInt16 old_hex_buf_len = hex_buf_len;

            if (old_hex_buf_len == 0)
            {
                return null;
            }

            hex_buf_temp[index++] = DLE;
            hex_buf_temp[index++] = STX;

            for (UInt16 i = 0; i < old_hex_buf_len; i++)
            {
                if (hex_buf[i] == DLE)
                {
                    hex_buf_temp[index++] = DLE;
                    hex_buf_temp[index++] = hex_buf[i];
                }
                else
                {
                    hex_buf_temp[index++] = hex_buf[i];
                }
            }

            hex_buf_temp[index++] = DLE;
            hex_buf_temp[index++] = ETX;

            // hex_buf_temp.CopyTo(hex_buf, 0);
            hex_buf_len = index;

            byte[] result = new byte[hex_buf_len];
            for (int i = 0; i < hex_buf_len; i++)
                result[i] = hex_buf_temp[i];

            return result;
        }
    }
}